﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Luna;

namespace TextDataExtractor.DEML {
	public abstract class AbstractPattern : DemlElement {

		public bool IsSuccess { get; protected set; }

		public bool Skipped { get; protected set; }

		public virtual string MatchedText { get; protected set; }

		public int StartIndex { get; protected set; }

		public int EndIndex { get; protected set; }

		public virtual int match(StreamReader input, ref string buffer) {
			return 0;
		}

		public virtual int match(String input) {
			return 0;
		}

		public virtual IEnumerable<AbstractPattern> getMatchedPatterns(Predicate<AbstractPattern> pred) {
			if (IsSuccess && pred(this))
				yield return this;
		}

		public virtual void performExtraction(ExecutionContext context) {
			if (IsSuccess) {
				// keep old active pattern and update it with self.
				AbstractPattern activePat = context.ActivePattern;
				context.ActivePattern = this;
				if (Name.isNotNullAndEmpty())
					context[Name] = this;
				try {
					doExtraction(context);
				}
				finally {
					// recover active pattern
					context.ActivePattern = activePat;
				}
			}
		}

		protected virtual void doExtraction(ExecutionContext context) {
			foreach (IDemlElement sube in Children)
				if (sube is AbstractAction)
					(sube as AbstractAction).execute(context);
				else if (sube is AbstractPattern)
					(sube as AbstractPattern).performExtraction(context);
		}

		protected override void processChildNode(System.Xml.XmlNode child, DemlRegistry registry) {
			if (DemlFactory.Instance.isElementType(ElementType.ExtractAction, child.Name)) {
				AbstractAction action = (AbstractAction)DemlFactory.Instance.createElement(ElementType.ExtractAction, child.Name);
				if (action != null) {
					action.loadFromXml(child, registry);
					Children.Add(action);
				}
			}
		}

		public virtual string getMatchedPatternName(int indent) {
			return new string('\t', indent) + this.Name;
		}
	}
}
